/***************************************************************************
 * Copyright 2012-2013 TXT e-solutions SpA
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the contract ICT-257367.
 *
 * Authors:
 *      Salvatore Piccione (TXT e-solutions SpA)
 *
 * Contributors:
 *        Domenico Rotondi (TXT e-solutions SpA)
 **************************************************************************/
package it.txt.ens.client.gui.standalone.util;

import it.txt.ens.client.application.exception.ApplicationFailureException;
import it.txt.ens.client.core.ENSClient;
import it.txt.ens.client.core.factory.ENSBrokerConnectionParametersFactory;
import it.txt.ens.client.core.factory.ENSClientFactory;
import it.txt.ens.client.exception.ENSClientException;
import it.txt.ens.client.impl.BasicENSBrokerConnectionParameters.BasicENSBrokerConnectionParametersFactory;
import it.txt.ens.client.publisher.impl.BasicENSPublisher.BasicENSPublisherFactory;
import it.txt.ens.client.subscriber.factory.ENSEventFactory;
import it.txt.ens.client.subscriber.impl.BasicENSEventFactory;
import it.txt.ens.client.subscriber.impl.BasicENSSubscriber.BasicENSSubscriberFactory;
import it.txt.ens.core.ENSAuthzServiceConnectionParameters;
import it.txt.ens.core.ENSResource;
import it.txt.ens.core.KeystoreParameters;
import it.txt.ens.core.X509CertificateRetrievalParameters;
import it.txt.ens.core.exception.ENSConnectionException;
import it.txt.ens.core.impl.BasicENSAuthzServiceConnectionParameters.BasicENSConnectionParametersFactory;
import it.txt.ens.core.impl.BasicENSResource.BasicENSResourceFactory;
import it.txt.ens.core.impl.BasicKeystoreParameters.BasicKeystoreParametersFactory;
import it.txt.ens.core.impl.BasicX509CertificateRetrievalParameters.BasicX509CertificateRetrievalParametersFactory;
import it.txt.ens.core.util.parser.ENSConnectionParametersMapParser;
import it.txt.ens.core.util.parser.ENSResourceMapParser;
import it.txt.ens.core.util.parser.KeystoreParametersMapParser;
import it.txt.ens.core.util.parser.ParseException;
import it.txt.ens.core.util.parser.X509CertificateRetrievalParametersMapParser;
import it.txt.ens.schema.factory.ENSRequestFactoryException;
import it.txt.ens.schema.factory.ENSResponseFactoryException;
import it.txt.ens.schema.request.factory.ENSAuthorisationRequestFactory;
import it.txt.ens.schema.request.factory.ENSAuthorisationRequestFactoryImpl;
import it.txt.ens.schema.response.factory.ENSAuthorisationResponseFactory;
import it.txt.ens.schema.response.factory.ENSAuthorisationResponseFactoryImpl;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;

/**
 * This class is in charge of starting the appropriate Guest Application
 * 
 * @author Salvatore Piccione (TXT e-solutions SpA - salvatore.piccione AT txtgroup.com)
 *
 */
public class RequestFactory {
    
    public static enum OperationTypes {
        PUBLISH("publish"),
        SUBSCRIBE("subscribe"),
        LA_PUBLISH("logging and audit publish");
        private String label;
        private OperationTypes(String label) {
            this.label = label;
        }
        public static OperationTypes getOperationType (String opName) {
            OperationTypes[] values = values();
            int i = 0;
            OperationTypes op = null;
            while (i < values.length && op == null) {
                if (values[i].label.equals(opName))
                    op = values[i];
                else
                    i++;
            }
            return op;
        }
    }
    
    public static class ExtraSettings4Publisher {
        public static final String ENTITY_DATA_URI = "edURI";
        public static final String ENTITY_URI = "eURI";
        public static final String MAX_RANDOM = "maxRnd";
        public static final String MIN_RANDOM = "minRnd";
        public static final String DELAY = "delay";
        public static final int DEFAULT_MAX_RANDOM = 10;
        public static final int DEFAULT_MIN_RANDOM = 1;
    }
    
    public static class ExtraSettings {
//        public static final String USER_ID = "uID";
//        public static final String NAMESPACE = "namespace";
//        public static final String PATTERN = "pattern";
//        public static final String RABBITMQ_HOST = "rmqHost";
//        public static final String RABBITMQ_PORT = "rmqPort";
    }
    
    private static final ENSAuthorisationRequestFactory REQUEST_FACTORY;
    private static final ENSAuthorisationResponseFactory RESPONSE_FACTORY;
            
    static {
//        String capabilitySchemasPath = ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
//                ApplicationPropertiesRepository.SCHEMAS_DIR);
        try {
//            if (capabilitySchemasPath == null || capabilitySchemasPath.isEmpty()) {
//                throw new RuntimeException(new AbstractApplicationException(
//                    "Unable to get capability schemas path system property."));
//            }
            REQUEST_FACTORY = ENSAuthorisationRequestFactoryImpl.getInstance(
                ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
                    ENSAuthorisationRequestFactory.SCHEMAS_DIRECTORY_PROP_KEY));
            System.out.println("Created ENSServiceRequestFactory instance");
            RESPONSE_FACTORY = ENSAuthorisationResponseFactoryImpl.getInstance(
                ApplicationPropertiesRepository.APPLICATION_PROPERTIES.getProperty(
                    ENSAuthorisationRequestFactory.SCHEMAS_DIRECTORY_PROP_KEY));
            System.out.println("Created ENSServiceResponseFactory instance");
        } catch (ENSRequestFactoryException e) {
            throw new RuntimeException(e);
        } catch (ENSResponseFactoryException e) {
            throw new RuntimeException(e);
        }
    }
    
	public static ENSClient startGuestApplication (String opName, HashMap<String,String> settings)
	        throws UnsupportedEncodingException, URISyntaxException, ApplicationFailureException,
	        IllegalArgumentException, ParseException, ENSRequestFactoryException, ENSResponseFactoryException {
	    
        String subjectID = settings.get(ENSClientFactory.SUBJECT_ID_KEY);
        ENSResource targetResource = ENSResourceMapParser.parse(new BasicENSResourceFactory(), settings);
        Date sessionExpiration;
        try {
            sessionExpiration = new SimpleDateFormat(ENSClientFactory.DATE_TIME_FORMAT).parse(
                    settings.get(ENSClientFactory.PREFERRED_SESSION_EXPIRATION_KEY));
        } catch (java.text.ParseException e) {
            throw new ApplicationFailureException(
                    "An error occurred while setting the preferred session expiration time", e);
        }
        ENSAuthzServiceConnectionParameters accessRequestBrokerConnParams =
                ENSConnectionParametersMapParser.parse(
                    new BasicENSConnectionParametersFactory(), settings);
        KeystoreParameters keystoreParams = KeystoreParametersMapParser.parse(
                new BasicKeystoreParametersFactory(), settings);
        X509CertificateRetrievalParameters certParams = X509CertificateRetrievalParametersMapParser.parse(
                new BasicX509CertificateRetrievalParametersFactory(), settings);
        File capabilityDirectory = new File (settings.get(ENSClientFactory.CAPABILITY_DIRECTORY_PATH_KEY));
        
        ENSBrokerConnectionParametersFactory connParamsFactory = new BasicENSBrokerConnectionParametersFactory();
        ENSEventFactory eventFactory = new BasicENSEventFactory();
        
	    try {
	        ENSClient client;
    	    if (opName.startsWith("publish")) {
	            client = new BasicENSPublisherFactory().create(subjectID, targetResource, sessionExpiration,
                    accessRequestBrokerConnParams, keystoreParams, certParams, capabilityDirectory,
                    REQUEST_FACTORY, RESPONSE_FACTORY, connParamsFactory);
    	    }
    	    else if (opName.startsWith("subscribe")) {
	            client = new BasicENSSubscriberFactory().create(subjectID, targetResource, sessionExpiration, 
	                    accessRequestBrokerConnParams, keystoreParams, certParams, capabilityDirectory,
                    REQUEST_FACTORY, RESPONSE_FACTORY, connParamsFactory, eventFactory);
    	    } else
    	        throw new IllegalArgumentException("No operation available for label '" + opName + "'");
            client.connect();
            return client;
	    } catch (ENSClientException e) {
	        String failureMsg = "A failure occurred while running the application";
            throw new ApplicationFailureException(failureMsg, e);
        } catch (ENSConnectionException e) {
            String failureMsg = "A failure occurred while running the application";
            throw new ApplicationFailureException(failureMsg, e);
        }
	}
}
